﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcDeveloper.Infrastructure.Routing;

namespace MvcDeveloper.UnitTests
{
    public static class RouteValueDictionaryExtenstion
    {
        public static string GenerateMvcUrl(this RouteValueDictionary values, params string[] urlParameters)
        {
            var url = new StringBuilder();

            if (!(values.ContainsKey("controller") || values.ContainsKey("action")))
            {
                return String.Empty;
            }
            
            url.AppendFormat("/{0}/{1}", values["controller"], values["action"]);

            foreach (var urlParameter in urlParameters)
            {
                if (values.ContainsKey(urlParameter))
                {
                    url.AppendFormat("/{0}", values[urlParameter]);
                }
            }

            return url.ToString();
        }
    }

    [TestClass]
    public class HelpRouteUnitTest
    {
        private HelpRoute _helpRoute;

        [TestInitialize]
        public void Initialize_HelpRoute()
        {
            _helpRoute = new HelpRoute(
                url: "/Help/Show/{topic}", 
                legacyUrl: "~/LegacyContent/{filename}.html",
                routeHandler: new MvcRouteHandler());
        }

        [TestCleanup]
        public void Cleanup_HelpRoute()
        {
            _helpRoute = null;
        }

        [TestMethod]
        public void GetRouteData_RequestWithLegacyUrl_ReturnValidRouteData()
        {
            // Arrange
            var httpContext = GetFakeHttpContext("~/LegacyContent/RouteBase.html");

            // Act
            var routeData = _helpRoute.GetRouteData(httpContext);

            // Assert
            Assert.IsNotNull(routeData);
            Assert.IsTrue(StringComparer.InvariantCultureIgnoreCase.Compare("/Help/Show/RouteBase",
                                                                  routeData.Values.GenerateMvcUrl("topic")) == 0);
        }

        [TestMethod]
        public void GetRouteData_RequestWithMvcUrl_ReturnValidRouteData()
        {
            // Arrange
            var httpContext = GetFakeHttpContext("~/Help/Show/RouteBase");

            // Act
            var routeData = _helpRoute.GetRouteData(httpContext);

            // Assert
            Assert.IsNotNull(routeData);
            Assert.IsTrue(StringComparer.InvariantCultureIgnoreCase.Compare("/Help/Show/RouteBase",
                routeData.Values.GenerateMvcUrl("topic")) == 0);
        }

        [TestMethod]
        public void GetVirtualPath_RequestWithMvcUrl_ReturnValidVirtualPathData()
        {
            // Arrange
            var requestContext = new RequestContext(GetFakeHttpContext("~/Help/Show/RouteBase"), new RouteData());
            var values = new RouteValueDictionary();
            values.Add("controller", "Help");
            values.Add("action", "Show");
            values.Add("topic", "RouteBase");

            // Act
            var virtualPathData = _helpRoute.GetVirtualPath(requestContext, values);

            // Assert
            Assert.IsNotNull(virtualPathData);
            Assert.AreEqual("/Help/Show/RouteBase", virtualPathData.VirtualPath);
        }

        private HttpContextBase GetFakeHttpContext(string url = null, string httpMethod = "GET")
        {
            var request = new System.Web.Fakes.StubHttpRequestBase
                {
                    AppRelativeCurrentExecutionFilePathGet = () => url,
                    HttpMethodGet = () => httpMethod
                };

            var response = new System.Web.Fakes.StubHttpResponseBase
                {
                    ApplyAppPathModifierString = str => str
                };

            var context = new System.Web.Fakes.StubHttpContextBase
                {
                    RequestGet = () => request,
                    ResponseGet = () => response
                };

            return context;
        }
    }
}
